﻿using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.Exams;
using YAPACS.RisServer.Abstractions;

namespace YAPACS.RisServer.Services;

public class ExamValidationService : DomainService, IExamValidationService
{
    private readonly IRepository<ExamValidation, Guid> _examValidationRepository;

    public ExamValidationService(IRepository<ExamValidation, Guid> examValidationRepository)
    {
        _examValidationRepository = examValidationRepository;
    }

    private static (ExamValidationLevel? level, string message) Validate(Exam exam, ExamValidationItem validationItem)
    {
        if (exam.Fit(validationItem.Rule))
        {
            return (null, null);
        }
        else
        {
            return (validationItem.Level, validationItem.Name);
        }
    }

    public async Task<Dictionary<ExamValidationLevel, List<string>>> ValidateAsync(Exam exam, ExamValidationType type)
    {
        var result = new Dictionary<ExamValidationLevel, List<string>>();

        var validations = await _examValidationRepository
            .GetListAsync(v => v.IsActive && v.Type == type && v.DeviceType == exam.DeviceType && v.Department == exam.Department);

        validations = validations
            .Where(v => !string.IsNullOrWhiteSpace(v.EntryCriteria))
            .Where(v => exam.Fit(v.EntryCriteria))
            .OrderBy(v => v.Order)
            .ThenBy(v => v.CreationTime)
            .ToList();

        var hasError = false;

        foreach (var validation in validations)
        {
            var validationItems = validation.ExamValidationItems
                .Where(item => item.IsActive)
                .Where(item => !string.IsNullOrWhiteSpace(item.Rule))
                .OrderBy(item => item.Order)
                .ThenBy(item => item.CreationTime)
                .ToList();

            foreach (var validationItem in validationItems)
            {
                if (hasError && validationItem.Level == ExamValidationLevel.Info)
                {
                    continue;
                }

                var (level, message) = Validate(exam, validationItem);
                if (level.HasValue)
                {
                    if (level.Value == ExamValidationLevel.Error)
                    {
                        hasError = true;
                    }

                    if (result.TryGetValue(level.Value, out List<string> messages))
                    {
                        if (!messages.Contains(message))
                        {
                            messages.Add(message);
                        }
                    }
                    else
                    {
                        result[level.Value] = [message];
                    }
                }
            }
        }

        return result;
    }
}
